#include "Semaphore.h"
#include <cstddef>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Util.h"

namespace qy
{

Semaphore *Semaphore::create(const char *name, unsigned int value)
{
	//O_CREAT: create a semaphore if it doesn't exist
	//O_EXCL: error if create a semaphore which exists
	if(!name)
	{
		return NULL;
	}

	sem_t *s = sem_open(name, O_CREAT|O_EXCL, 0644, value);
	return s ? new Semaphore(*s) : NULL;
}

Semaphore *Semaphore::open(const char *name)
{
	Semaphore *sem = NULL;
	sem_t *s = sem_open(name, 0);
	return s ? new Semaphore(*s) : NULL;
}

Semaphore *Semaphore::create(unsigned int value)
{
	sem_t s;
	//pshared:0-shared among threads in this process, non-zero:shared among processes which can access this semaphore
	//sem_init is not supported on Mac OS
	if(sem_init(&s, 0, value) == 0)
	{
		Semaphore *sem = new Semaphore(s);
		return sem;
	}
	else
	{
		log_error("errno: %d", errno);
	}
	return NULL;
}

void Semaphore::destroy(Semaphore *s)
{
	delete_null(s);
}

bool Semaphore::unlink(const char *name)
{
	return 0 == sem_unlink(name);
}

bool Semaphore::wait()
{
	return sem_wait(&m_sem) == 0;
}

bool Semaphore::trywait()
{
	return sem_trywait(&m_sem) == 0;
}

bool Semaphore::post()
{
	return sem_post(&m_sem) == 0;
}

bool Semaphore::value(int &v)
{	
	return sem_getvalue(&m_sem, &v) == 0;
}

Semaphore::Semaphore(sem_t s, const char *name)
:m_sem(s)
{
	if(name)
	{
		m_name = std::string(name);
	}
}

Semaphore::~Semaphore()
{
	if(m_name.length() > 0)
	{
		//named semaphore
		//system resources related with the semaphore will be deallocated except for itself.
		//semaphore itself will be released when its reference number is 0
		sem_close(&m_sem);
	}
	else
	{
		//anonymous semaphore
		sem_destroy(&m_sem);
	}
}

}

